/* 
 * Copyright (C) 2012 UTSChedule
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package utsc.apps.utschedule.widget;

import java.util.ArrayList;

import utsc.apps.utschedule.R;
import utsc.apps.utschedule.classes.Course;
import utsc.apps.utschedule.ui.interfaces.ViewCallable;
import android.content.Context;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

/**
 * This is a custom layout widget to contain all the <code>{@link utsc.apps.utschedule.widget.TimeBlockView TimeBlockView}</code> objects with a <code>{@link utsc.apps.utschedule.widget.TimeRulerGridView  TimeRulerGridView}</code>.
 * @author Wenbin
 *
 */
public class TimeBlockLayout extends RelativeLayout {

	private TimeRulerGridView _timeRulerGridView;
	private GestureDetector _gestureDetector;
	private TimeBlockView _lastAddedBlockView;
	private OnClickListener _blockViewOnClickListener=null;
	//private HashMap<Integer, ArrayList<Course>> _courses;
	private boolean _showDay=false;
	private boolean _refreshView=false;
	private static final String EVENTBLOCK_TAG_PREFIX="eventblockview:";
	//private HashMap<Integer,WeakReference<EventBlockView>> _coursEventBlockViews;
	private ViewCallable<Course> _courseViewCallable;
	
	public TimeBlockLayout(Context context) {
		this(context, null);
	}

	public TimeBlockLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public TimeBlockLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		if (_gestureDetector==null) {
			//setup a gesture detector to differentiate if user is performing a single click or scroll on the scrollview
			_gestureDetector=new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){
				@Override
				public boolean onSingleTapUp(MotionEvent e) {
					//on any position the user has clicked on the widget, 
					//we try to convert the x y axis to match with the position indexes on the time ruler grid view
					TimeBlockView blockView=new TimeBlockView(getContext().getApplicationContext(), _timeRulerGridView.getTimeHourBlockPosition(e.getY()), _timeRulerGridView.getTimeColumnBlockPosition(e.getX()),_timeRulerGridView.get_columnWidth(),_timeRulerGridView.get_HourHeight(), R.layout.timeblockview);
					//remove the last added blockview
					removeView(_lastAddedBlockView);
					_lastAddedBlockView=null;
					//add the new blockview
					addBlock(blockView);
					//invalidate();
					return true;
				}
				@Override
				public boolean onDown(MotionEvent e) {
					return true;
				}
			});
		}
	}

	private void ensureChildren() {
		if (_timeRulerGridView == null) {
			_timeRulerGridView = (TimeRulerGridView) findViewById(R.id.timeRulerGridView);
			if (_timeRulerGridView==null) {
				throw new IllegalStateException(
						"Must include a R.id.timeRulerGridView1 view.");
			}
			
		}
		_showDay=_timeRulerGridView.get_column()==1;
		_timeRulerGridView.setDrawingCacheEnabled(true);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		ensureChildren();

		_timeRulerGridView.measure(widthMeasureSpec, heightMeasureSpec);
		// mNowView.measure(widthMeasureSpec, heightMeasureSpec);

		//we use the dimension of the time ruler grid view as of the widget dimension
		final int width = _timeRulerGridView.getMeasuredWidth();
		final int height = _timeRulerGridView.getMeasuredHeight();

		setMeasuredDimension(resolveSize(width, widthMeasureSpec),
				resolveSize(height, heightMeasureSpec));
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		ensureChildren();
		//Log.d(VIEW_LOG_TAG, "time block layout");
		final TimeRulerGridView rulerView = _timeRulerGridView;
		rulerView.measure(
				MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
				MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
		rulerView.layout(0, 0, getWidth(), getHeight());
		final int headerWidth = rulerView.getHeaderWidth();
		final int columnWidth = (rulerView.get_columnWidth());
		final int hourHeight = rulerView.get_HourHeight();

		final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE ) continue;

            //layout the block view 
            if (child instanceof TimeBlockView) {
                final TimeBlockView blockView = (TimeBlockView) child;
                //get the 4 coordinates on the widget for layout
                final int top = (blockView.get_hourPosition()-rulerView.get_StartHour())*hourHeight+1;
                final int bottom = top+hourHeight-1;
                final int left = (blockView.get_columnPosition()-1)*columnWidth+headerWidth+1;
                final int right = left + columnWidth-1;
                child.measure(MeasureSpec.makeMeasureSpec(right-left, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(bottom-top, MeasureSpec.EXACTLY));
                child.layout(left, top, right, bottom);
            }else if (child instanceof EventBlockView) {
            		final EventBlockView eventBlockView= (EventBlockView) child;
    				
    				final int top = _timeRulerGridView.getTimeVerticalOffset(eventBlockView.get_course().get_startTime());
                    final int bottom = _timeRulerGridView.getTimeVerticalOffset(eventBlockView.get_course().get_endTime());
                    final int left = (eventBlockView.get_columnPosition()-1)*columnWidth+headerWidth+1;
                    final int right = left + columnWidth-1;
                    child.measure(MeasureSpec.makeMeasureSpec(right-left, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(bottom-top, MeasureSpec.EXACTLY));
                    child.layout(left, top, right, bottom);
			}
        }
		 
	}
	
	public TimeRulerGridView get_timeRulerGridView() {
		return _timeRulerGridView;
	}
	
	/**
	 * Add a TimeBlockView to the layout.
	 * @param blockView - the new blockview to add
	 */
	public void addBlock(TimeBlockView blockView) {
        blockView.setDrawingCacheEnabled(true);
        _lastAddedBlockView=blockView;
        _lastAddedBlockView.setOnClickListener(_blockViewOnClickListener);
        addView(_lastAddedBlockView);
    }
	
	public boolean is_refreshView() {
		return _refreshView;
	}
	
	private void addCourse(Course c,boolean hidden){
		//c.set_hidden(hidden);
		/*if (_courses==null) {
			_courses=new HashMap<Integer, ArrayList<Course>>();
			//_coursEventBlockViews=new HashMap<Integer, WeakReference<EventBlockView>>();
		}else {
			int day=c.get_day();
			if (_courses.get(day) != null) {
				_courses.get(day).add(c);
				//Collections.sort(dayCourse);
			}else {
				ArrayList<Course> newDayCourse=new ArrayList<Course>();
				newDayCourse.add(c);
				_courses.put(day, newDayCourse);
			}
			
		}*/
		String tag=EVENTBLOCK_TAG_PREFIX+c.get_courseID();
		EventBlockView eventBlockView=(EventBlockView) findViewWithTag(tag);
		if (eventBlockView==null) {
			eventBlockView=new EventBlockView(getContext(),c.get_courseID(), (_showDay?1:c.get_day()), /*_timeRulerGridView.get_columnWidth(), bottom-top,*/ c,_showDay);
			eventBlockView.setTag(tag);
			eventBlockView.set_updateCallable(_courseViewCallable);
			eventBlockView.setOnClickListener(_blockViewOnClickListener);
			eventBlockView.setVisibility(hidden?View.INVISIBLE:View.VISIBLE);
			addView(eventBlockView,1);
			//addViewInLayout(eventBlockView, -1, getLayoutParams(),false);
		}else {
			//eventBlockView.set_updateCallable(_courseViewCallable);
			//eventBlockView.setOnClickListener(_blockViewOnClickListener);
			eventBlockView.set_course(c);
			eventBlockView.setVisibility(hidden?View.INVISIBLE:View.VISIBLE);
			
			
		}
		
		//eventBlockView.setDrawingCacheEnabled(true);
		//_coursEventBlockViews.put(c.get_courseID(),new WeakReference<EventBlockView>(eventBlockView));
		
	}
	
	public void refreshCourseBlocks(ArrayList<Course> courses,int weekday, SparseBooleanArray showOddWeek,ViewCallable<Course> callable) {
		ensureChildren();
		if (_courseViewCallable==null) {
			_courseViewCallable=callable;
		}
		if (courses != null && courses.size() > 0) {
			/*if (_refreshView && _courses != null) {
				_courses.clear();
			}*/
			//boolean refresh=_refreshView;
			for (Course course : courses) {

				if (_refreshView) {
					
					addCourse(course, (!showOddWeek.get(course.get_oddWeeks())||course.get_day()!=weekday));
				} else {
					String tag = EVENTBLOCK_TAG_PREFIX + course.get_courseID();
					View v = findViewWithTag(tag);
					if (v!=null) {
						if (course.get_day()!=weekday) {
							v.setVisibility(View.INVISIBLE);
						}else {
							if (showOddWeek.get(course.get_oddWeeks())) {
								v.setVisibility(View.VISIBLE);
							} else {
									v.setVisibility(View.INVISIBLE);
							}
						}
						
					}else {
						addCourse(course, (!showOddWeek.get(course.get_oddWeeks())||course.get_day()!=weekday));
					}
					
					
				}

			}
		}
	}
	
	/*private boolean hideOddWeekCourseBlocks(Course c, HashMap<Integer, Boolean> showOddWeek){
		boolean hidden=false;
		if (showOddWeek!=null) {
			if (!showOddWeek.isEmpty()) {
					if (showOddWeek.get(c.get_oddWeeks())) {
						hidden=false;
					}else {
						hidden=true;
					}
			}else {
				hidden=false;
			}
		}
		
		return hidden;
	}*/
	
	public void refreshCourseBlocks(ArrayList<Course> courses, SparseBooleanArray showOddWeek, ViewCallable<Course> callable){
		//Log.d("oddweek", showOddWeek+"");
		ensureChildren();
		if (_courseViewCallable==null) {
			_courseViewCallable=callable;
		}
		if (courses != null && courses.size() > 0) {
			/*if (_refreshView && _courses != null) {
				_courses.clear();
			}*/
			//boolean refresh=_refreshView;
			for (Course course : courses) {

				if (_refreshView) {
					addCourse(course, !showOddWeek.get(course.get_oddWeeks()));
				} else {
					String tag = EVENTBLOCK_TAG_PREFIX + course.get_courseID();
					View v = findViewWithTag(tag);
					if (v!=null) {
						if (showOddWeek.get(course.get_oddWeeks())) {
							if (v != null) {
								v.setVisibility(View.VISIBLE);
							}
						} else {
							if (v != null) {
								v.setVisibility(View.INVISIBLE);
							}

						}

					}else {
						addCourse(course, !showOddWeek.get(course.get_oddWeeks()));
					}
				}

			}
		}
	}

	/**
	 * Setup the on click listener of the TimeBlockView.
	 * @param _blockViewOnClickListener
	 */
	public void set_blockViewOnClickListener(
			OnClickListener _blockViewOnClickListener) {
		this._blockViewOnClickListener = _blockViewOnClickListener;
		int size=getChildCount();
		for (int i = 0; i < size; i++) {
			View v=getChildAt(i);
			if (v instanceof EventBlockView) {
				v.setOnClickListener(_blockViewOnClickListener);
			}
		}
	}
	
	public  OnClickListener get_blockViewOnClickListener() {
		return _blockViewOnClickListener;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (!isEnabled()) {
			return false;
		}
		//delegate the touchevent to our gesturedetector
		return _gestureDetector.onTouchEvent(event);
	}
	
	public void set_refreshView(boolean refreshView) {
		_refreshView = refreshView;
	}

	public void updateCourseLayout(int courseid,boolean updateEndtime) {

		EventBlockView eventBlockView=(EventBlockView) findViewWithTag(EVENTBLOCK_TAG_PREFIX+courseid);// _coursEventBlockViews.get(courseid).get();
		
		
		final int l=eventBlockView.getLeft();
		
		final int r=eventBlockView.getRight();
		 int t=0;
		 int b=0;
		if (updateEndtime) {
			t = eventBlockView.getTop();
			b = _timeRulerGridView.getTimeVerticalOffset(eventBlockView.get_course().get_endTime());
		} else {
			t = _timeRulerGridView.getTimeVerticalOffset(eventBlockView.get_course().get_startTime());
			b = eventBlockView.getBottom();
		}
		
		eventBlockView.layout(l, t, r, b);
	}
	/*public int getCoursesCount() {
		if (_courses==null) {
			return 0;
		}else {
			return _courses.size();
		}
	}*/
}
